package com.github.editor.zip;


import com.github.editor.util.FileUtil;
import org.apache.commons.compress.archivers.jar.JarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;

import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;

public class ApacheZipUtil extends IZipUtil {

    @Override
    public void createNew(String srcPath, String dstPath, Map<String, String> updateList) throws IOException {
        //AndroidManifest.xml
        File outputFile = new File(dstPath);
        File dir = outputFile.getParentFile();
        if(dir != null){
            if(dir.isFile()){
                dir.delete();
            }
            if(!dir.exists()) {
                dir.mkdirs();
            }
        }
        if(outputFile.exists()){
            outputFile.createNewFile();
        }
        if(dir != null && !dir.exists()){
            throw new IOException("create dir error:"+dir.getAbsolutePath());
        }
        Map<String, ZipArchiveEntry> oldMap = new HashMap<>();
        try (ZipFile zipFile = new ZipFile(srcPath);
             FileOutputStream outputStream = new FileOutputStream(outputFile);
             JarArchiveOutputStream zipArchiveOutputStream = new JarArchiveOutputStream(outputStream)) {
            Enumeration<ZipArchiveEntry> enumeration = zipFile.getEntries();
            //原样拷贝
            while (enumeration.hasMoreElements()) {
                ZipArchiveEntry zipArchiveEntry =  enumeration.nextElement();
                if(updateList.containsKey(zipArchiveEntry.getName())){
                    oldMap.put(zipArchiveEntry.getName(), zipArchiveEntry);
                    continue;
                }
                zipArchiveOutputStream.putArchiveEntry(zipArchiveEntry);
                if(!zipArchiveEntry.isDirectory()){
                    FileUtil.copy(zipFile.getInputStream(zipArchiveEntry), zipArchiveOutputStream);
                }
                zipArchiveOutputStream.closeArchiveEntry();
            }
            for(Map.Entry<String, String> item : updateList.entrySet()) {
                String entryName = item.getKey();
                String file = item.getValue();
                ZipArchiveEntry old = oldMap.get(entryName);
                //添加文件
                ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(entryName);
                if (old != null) {
                    zipArchiveEntry.setMethod(old.getMethod());
                    zipArchiveEntry.setTime(old.getTime());
                    //System.out.println(entryName+"'s crc="+old.getCrc());
                    //System.out.println(entryName + ":" + old.getMethod() + "->" + zipArchiveEntry.getMethod());
                } else {
                    zipArchiveEntry.setMethod(ZipEntry.DEFLATED);
                    zipArchiveEntry.setTime(347130062000L);
                }
                zipArchiveEntry.setSize(new File(file).length());
                if(zipArchiveEntry.getMethod() == ZipEntry.STORED) {
                    zipArchiveEntry.setCrc(getCrc32(file));
                    try (FileInputStream inputStream = new FileInputStream(file)) {
                        zipArchiveOutputStream.addRawArchiveEntry(zipArchiveEntry, inputStream);
                    }
                } else {
                    zipArchiveOutputStream.putArchiveEntry(zipArchiveEntry);
                    try (FileInputStream inputStream = new FileInputStream(file)) {
                        FileUtil.copy(inputStream, zipArchiveOutputStream);
                    }
                    zipArchiveOutputStream.closeArchiveEntry();
                }
            }
        }
    }

    @Override
    public void ReadZipEntry(String zip, String name, OutputStream outputStream) throws IOException {
        try (ZipFile zipFile = new ZipFile(zip)) {
            ZipArchiveEntry zipEntry = zipFile.getEntry(name);
            if (zipEntry == null) {
                throw new IOException("not found entry:" + name);
            }
            try (InputStream inputStream = zipFile.getInputStream(zipEntry);
            ) {
                FileUtil.copy(inputStream, outputStream);
            } catch (Throwable e) {
                //ignore
            }
        }
    }

    @Override
    public void exportFiles(String zip, String output, String... names) throws IOException {
        try (ZipFile zipFile = new ZipFile(zip)) {
            for(String name : names) {
                ZipArchiveEntry zipEntry = zipFile.getEntry(name);
                if (zipEntry == null) {
                    throw new IOException("not found entry:" + name);
                }
                File file = new File(output, name);
                File dir = file.getParentFile();
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                try (InputStream inputStream = zipFile.getInputStream(zipEntry);
                     FileOutputStream outputStream = new FileOutputStream(file);
                ) {
                    FileUtil.copy(inputStream, outputStream);
                } catch (Throwable e) {
                    //ignore
                }
            }
        }
    }

}
